package org.ezaero.jmimic.api.checker;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Arrays;

import org.ezaero.jmimic.impl.store.xstream.XStreamFactory;

import com.thoughtworks.xstream.XStream;

public class BinaryComparisonChecker implements InvocationChecker {

    private final XStream xstream = XStreamFactory.createBinary();

    @Override
    public boolean checkInvocation(String actualMethod, Object[] actualArgs, String expectedMethod, Object[] expectedArgs) {
        if (!actualMethod.equals(expectedMethod)) {
            return false;
        }

        if (actualArgs.length != expectedArgs.length) {
            return false;
        }

        for (int i = 0; i < actualArgs.length; i++) {
            final Object a = actualArgs[i];
            final Object b = expectedArgs[i];

            if (!compare(a, b)) {
                return false;
            }
        }

        return true;
    }

    @Override
    public boolean checkResponse(String actualMethod, Object actualValue, String expectedMethod, Object expectedValue) {
        if (!actualMethod.equals(expectedMethod)) {
            return false;
        }
        return compare(expectedValue, actualValue);
    }

    protected boolean compare(Object a, Object b) {
        if (a == b) {
            return true;
        }

        if (a == null) {
            if (b != null) {
                return false;
            }
        } else {
            if (b == null) {
                return false;
            }

            try {
                final ByteArrayOutputStream outA = new ByteArrayOutputStream(2048);
                xstream.toXML(a, outA);
                outA.close();

                final ByteArrayOutputStream outB = new ByteArrayOutputStream(2048);
                xstream.toXML(b, outB);
                outB.close();

                if (!Arrays.equals(outA.toByteArray(), outB.toByteArray())) {
                    return false;
                }
            } catch (IOException e) {
                throw new IllegalStateException(String.format("Failed to do binary comparison, where a=%s, b=%s", a, b), e);
            }
        }

        return true;
    }
}
